/// Script generating definitions used by the `<FileTree>` component and associated SVGs.
///
/// To do so, it clones the Seti UI repository, installs dependencies, generates icons, parses the
/// mapping to generate the definitions and a list of icons to extract as SVGs, and finally extracts
/// the SVGs from the font and writes the definitions and SVGs to the jaspr_content package in a file
/// ready to be consumed by jaspr_content.
library;

import 'dart:convert';
import 'dart:io';

import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path;

void main() async {
  final iconDefinitions = await fetchIconDefinitions();

  await writeDefinitionsAndSVGs(
    iconDefinitions.$1,
    iconDefinitions.$2,
  );
}

Future<(Map<String, dynamic>, Map<String, String>)> fetchIconDefinitions() async {
  const url =
      'https://raw.githubusercontent.com/withastro/starlight/refs/heads/main/packages/starlight/user-components/file-tree-icons.ts';
  final response = await http.get(Uri.parse(url));
  final jsContent = response.body;

  final definitionsMatch = RegExp(
    'export const definitions: Definitions = (\\{.*?\\});',
    dotAll: true,
  ).firstMatch(jsContent);
  if (definitionsMatch == null) {
    throw Exception('Could not find definitions in the downloaded file.');
  }

  final definitionsJson = definitionsMatch
      .group(1)!
      // Fix all non-quoted keys to make it valid JSON.
      .replaceAllMapped(RegExp(r'\s(\w+):\s'), (match) => " '${match.group(1)}': ")
      // Fix single quotes to double quotes.
      .replaceAll("'", '"')
      // Remove trailing commas.
      .replaceAll(RegExp(r',\s*}'), ' }');
  final definitions = jsonDecode(definitionsJson) as Map<String, dynamic>;

  for (final value in definitions.values) {
    // Remove all custom icons added by Starlight that are not part of Seti.
    (value as Map<String, dynamic>).removeWhere((_, value) => !(value as String).startsWith('seti:'));
  }

  final iconsMatch = RegExp('export const FileIcons = ({.*?});', dotAll: true).firstMatch(jsContent);
  if (iconsMatch == null) {
    throw Exception('Could not find icons in the downloaded file.');
  }

  final iconsJson = iconsMatch
      .group(1)!
      .replaceAll('"', r'\"')
      // Fix single quotes to double quotes.
      .replaceAll("'", '"')
      // Remove trailing commas.
      .replaceAll(RegExp(r',\s*}'), ' }');
  final icons = jsonDecode(iconsJson) as Map<String, dynamic>;

  return (definitions, icons.cast<String, String>());
}

const copyrightNotice = '''
// Based on https://github.com/elviswolcott/seti-icons
//
// Copyright (c) 2014 Jesse Weed
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
''';

const generatedFileHeader = '''
// GENERATED FILE - DO NOT EDIT
// This file was generated by the 'tool/file_icons_generator' package.

// dart format off
''';

/// Write the generated definitions and SVGs to the jaspr_content package.
Future<void> writeDefinitionsAndSVGs(Map<String, dynamic> definitions, Map<String, String> svgPaths) async {
  final content =
      '''
$generatedFileHeader
$copyrightNotice
const definitions = ${JsonEncoder.withIndent('  ').convert(definitions)};

const fileIcons = ${JsonEncoder.withIndent('  ').convert(svgPaths)};
''';

  final filePath = path.join('..', '..', 'lib', 'components', '_internal', 'file_tree_icons.dart');

  await File(filePath).writeAsString(content);
}
